<?php

namespace App\Models;

use App\Contacts\Exp;
use App\Http\Resources\Customers;
use App\Http\Resources\OrderItems;
use App\Models\Traits\HasHint;
use \Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;

class Order extends Model
{
    use SoftDeletes, HasHint;

    const PAYMENT_OFFLINE = 1;
    const PAYMENT_ALIPAY = 2;
    const PAYMENT_WECHAT = 3;
    const PAYMENT_SELF = 4; // 钱包支付

    public static $payment = [
        self::PAYMENT_OFFLINE => '线下转账',
        self::PAYMENT_ALIPAY => '支付宝',
        self::PAYMENT_WECHAT => '微信',
        // self::PAYMENT_SELF => '钱包支付',
    ];

    protected $fillable = [
        'customer_id', // 顾客ID
        'order_number', // 订单号
        'address', // 地址
        'total_account', // 总金额
        'total_amount', // 总数量
        'remark', // 备注
        'paid_at', // 支付时间
        'payment_method', // 支付方式
        'payment_money', // 支付金额
        'payment_supplement', // 补充支付方式: 固定为: 4-钱包支付
        'supplement_payment_money', // 补充支付金额
        'payment_no', // 支付流水号
        'refund_no', // 退款订单号
        'ship_data', // 物流详情
        'extra', // 额外信息
        'cancel_at', // 自动取消时间

        // 弃用字段
        'refund_status', // @弃用: 退款状态
        'closed', // @弃用: 是否关闭
        'reviewed', // @弃用: 是否评论
        'ship_status', // @弃用: 配送状态
        'close_reason', // @弃用: 关闭原因
    ];

    protected $casts = [
        'closed' => 'boolean',
        'reviewed' => 'boolean',
        'address' => 'json',
        'ship_data' => 'json',
        'extra' => 'json',
    ];

    protected $dates = [
        'paid_at',
        'created_at',
        'updated_at',
    ];

    protected static function boot()
    {
        parent::boot();
        // 监听模型创建事件，在写入数据库之前触发
        static::saving(function ($model) {
            // 如果模型的 order_number 字段为空
            if (!$model->order_number) {
                // 调用 findAvailableNo 生成订单流水号
                $model->order_number = static::findAvailableNo();
                // 如果生成失败，则终止创建订单
                if (!$model->order_number) {
                    return false;
                }
            }
        });
    }

    public function scopeStatus(Builder $builder, $status)
    {
        switch ($status) {
            case 'ship': // 待收货
                $builder->whereHas('hint', function (Builder $q) {
                    $q->whereIn('class', [
                        UnShipHintStatus::class,
                        UnReceivedHintStatus::class,
                    ]);
                });
                break;
            case 'comment': // 待评价
                $builder->whereHas('hint', function (Builder $q) {
                    $q->whereIn('class', [
                        UnCommentHintStatus::class,
                    ]);
                });
                break;
            case 'pay': // 待付款
                $builder->whereHas('hint', function (Builder $q) {
                    $q->whereIn('class', [
                        UnPayHintStatus::class,
                        OfflineUnPayHintStatus::class,
                        PayingHintStatus::class,
                    ]);
                });
                break;
            case 'cancel': // 已取消
                $builder->whereHas('hint', function (Builder $q) {
                    $q->whereIn('class', [
                        CancelHintStatus::class,
                    ]);
                });
                break;
            case 'refund': // 退换货中
                $builder->whereHas('hint', function (Builder $q) {
                    $q->whereIn('class', [
                        RefundAppliedHintStatus::class,
                        RefundFailureHintStatus::class,
                        RefundSuccessHintStatus::class,
                        RefundDoneHintStatus::class,
                        RefundCancelHintStatus::class,
                    ]);
                });
                break;
            case 'all': // 默认全部订单
            default:
                break;
        }

        return $builder;
    }

    public function customer()
    {
        return $this->belongsTo(Customer::class);
    }

    public function items()
    {
        return $this->hasMany(OrderItem::class);
    }

    // 订单支付
    public function pay($amount, $payment)
    {
        if ($payment === self::PAYMENT_SELF) {
            $this->update([
                'payment_supplement' => $payment,
                'supplement_payment_money' => $amount,
            ]);
        } else {
            $this->update([
                'payment_method' => $payment, // 支付方式
                'payment_money' => $amount, // 支付金额
            ]);
        }
    }

    // 订单退款
    public function refund($payment = null)
    {
        if ($this->getHint()->isFinish()) {
            return;
        }

        if (is_null($payment)) {// 全额退款
            $amount = $this->total_account * 100;
        } else {

            if ($payment == self::PAYMENT_SELF) {// 钱包退款
                $amount = $this->supplement_payment_money;
            } else {// 其他支付方式
                $amount = $this->payment_money;
            }
        }

        // 退款到钱包
        Pocket::getPocket($this->customer_id)->recharge($amount, 'YS-' . $this->order_number);
    }

    // 订单完成
    public function done($hasComment = true)
    {
        if (!$hasComment) {
            $this->autoComment();
        }

        // 刷新一下物流信息
        $com = $this->ship_data['exp'];
        $code = $this->ship_data['exp_no'];
        $this->refreshShipData($com, $code);

        // 修改状态
        return $this->getHint()->done();
    }

    // 自动好评
    public function autoComment()
    {
        $this->items->map(function ($item) {
            $item->comment([
                "content" => "好评!",
                "score" => 5,
                "level" => 1,
            ], []);
        });
    }

    // 生成订单号
    public static function findAvailableNo()
    {
        do {
            // 订单流水号前缀
            $prefix = date('YmdHis');
            // 随机6位数字
            $no = $prefix . str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
        } while (static::query()->where('order_number', $no)->exists());

        return $no;
    }

    // 获取商品总价, 除去优惠价格
    public static function price($products, $coupons = [])
    {
        /**
         * 使用 分 作为单位进行计算, 防止在程序执行中因精度问题导致结果不准确
         */
        $total = 0;

        foreach ($products as $id => $price) {
            $price = $price * 100;
            if ($coupons && isset($coupons[$id])) {
                $price = $price - $coupons[$id] * 100;
            }

            $total += $price;
        }

        return price($total / 100);
    }

    public static function hasNewOrder($data, $products)
    {
        $order = new static();

        foreach ($data as $field => $value) {
            $order->setAttribute($field, $value);
        }

        DB::beginTransaction();
        try {
            // 保存订单
            $order->save();

            // 遍历订单中的所有商品
            foreach ($products as $sku) {
                $cover = $sku->cover ?: $sku->product->cover;

                // 订单明细
                $order->items()->create([
                    'product_id' => $sku->product_id,
                    'product_sku_id' => $sku->id,
                    'amount' => $sku->number,
                    'price' => $sku->price,
                    'detail' => [
                        'cover' => $cover ? ['host' => $cover->host, 'path' => $cover->path] : null,
                        'name' => $sku->product->name,
                        'attribute' => $sku->description,
                    ],
                ]);

                // 移除购物车
                Cart::remove($order->customer_id, $sku->product_id, $sku->id);

                // 减少库存
                if ($sku->decreaseStock($sku->number)) {
                    // 添加销量
                    if (!$sku->product->increment('count_sales', $sku->number)) {
                        throw new Exception("系统异常");
                    }
                } else {
                    throw new Exception("库存不足");
                }
            }
            DB::commit();
        } catch (Exception $e) {
            DB::rollBack();
            return $e->getMessage();
        }

        return $order;
    }

    public function getShipDetail()
    {
        if ($this->getHint()->isShip()) {
            $com = $this->ship_data['exp'];
            $code = $this->ship_data['exp_no'];

            $detail = Cache::get(self::shipDataCacheKey($com, $code));

            return $detail ?: $this->refreshShipData($com, $code);
        } elseif ($this->getHint()->isFinish()) {
            return $this->ship_data;
        }

        return null;
    }

    private function refreshShipData($com, $code)
    {
        $data = app(Exp::class)->information($code, $com);

        $detail = $this->ship_data;

        $detail['detail'] = $data;

        $this->update(['ship_data' => $detail]);

        Cache::put(self::shipDataCacheKey($com, $code), $detail, now()->addHours(4));

        return $data;
    }

    private static function shipDataCacheKey($com, $no)
    {
        return $com . "_" . $no;
    }

    public function display()
    {
        return [
            'id' => $this->id,
            'items' => OrderItems::collection($this->items),
            'customer' => Customers::make($this->customer),
            'address' => [
                'contact_name' => $this->address['contact_name'],
                'contact_phone' => $this->address['contact_phone'],
                'address' => getAllAddress($this->address),
            ],
            'total_account' => $this->total_account,
            'total_amount' => $this->total_amount,
            'remark' => $this->remark,
            'payment_method' => $this->payment_method,
            'refund_status' => $this->refund_status,
            'ship_data' => $this->getShipDetail(),
            'extra' => $this->extra,
            'status' => $this->status,
            'paid_at' => (string)$this->paid_at,
            'created_at' => (string)$this->created_at,
            'cancel_at' => $this->cancel_at, // 自动取消时间戳
        ];
    }
}
